'use client'
import { useState, useEffect, useRef, useCallback } from 'react'
import { useAuth } from '@/components/AuthProvider'
import { LoginButton } from '@/components/LoginButton'
import Editor from '@/components/Editor'
import ChatPanel from '@/components/ChatPanel'
import ResizablePanel from '@/components/ResizablePanel'
import { FileSystemItem } from '@/lib/types/database'
import { useFileSystem } from '@/lib/hooks/useFileSystem'
import { usePageLifecycle } from '@/lib/hooks/usePageLifecycle'
import { IoDocumentsOutline, IoSearchOutline, IoArrowBackOutline, IoGitBranchOutline, IoDocumentTextOutline, IoChatbubblesOutline, IoTimeOutline, IoSparklesOutline } from 'react-icons/io5'
import { useRouter } from 'next/navigation'
import ExplorerTab from '@/components/ExplorerTab'
import UnifiedSearchTab from '@/components/UnifiedSearchTab'
import DifferencesTab from '@/components/DifferencesTab'
import DownloadDropdown from '@/components/DownloadDropdown'
import DiffViewer from '@/components/DiffViewer'
import BookEditorSkeleton from '@/components/BookEditorSkeleton'
interface PageProps {
params: {
id: string
}
}
interface BookInfo {
id: string
title: string
description?: string
}
export default function BookEditor({ params }: PageProps) {
const { user, loading: authLoading } = useAuth()
const [selectedFile, setSelectedFile] = useState<FileSystemItem | null>(null)
const [activeTab, setActiveTab] = useState<'explorer' | 'search' | 'differences'>('explorer')
const [mobileView, setMobileView] = useState<'explorer' | 'editor' | 'assistant'>('explorer') // Mobile view state
const [mobileTab, setMobileTab] = useState<'back' | 'explorer' | 'search' | 'differences'>('explorer') // Mobile tab state
const [bookInfo, setBookInfo] = useState<BookInfo | null>(null)
const [bookLoading, setBookLoading] = useState(true)
const [initialFilesLoading, setInitialFilesLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [editorInstance, setEditorInstance] = useState<any>(null) // TipTap editor instance
// Diff mode state
const [showDiffMode, setShowDiffMode] = useState(false)
const [diffInfo, setDiffInfo] = useState<{
originalContent: string
modifiedContent: string
fileName: string
} | null>(null)
const router = useRouter()
const lastVisibilityChangeRef = useRef<number>(Date.now())
const isInitializedRef = useRef(false)
const pageLifecycle = usePageLifecycle()
// Check if device is mobile
const isMobile = () => typeof window !== 'undefined' && window.innerWidth < 768
const {
files,
loading: filesLoading,
error: filesError,
fetchFiles,
updateItem,
createItem,
deleteItem,
forceRefreshFiles
} = useFileSystem()
// Handle page visibility changes to prevent unnecessary reloads
useEffect(() => {
const handleVisibilityChange = () => {
const now = Date.now()
if (!document.hidden && document.visibilityState === 'visible') {
// Page became visible
if (pageLifecycle.shouldRefreshData()) {
if (user && params.id && isInitializedRef.current) {
fetchFiles(params.id)
}
}
}
lastVisibilityChangeRef.current = now
}
document.addEventListener('visibilitychange', handleVisibilityChange)
return () => document.removeEventListener('visibilitychange', handleVisibilityChange)
}, [user, params.id, fetchFiles, pageLifecycle])
// Handle window resize for responsive layout
useEffect(() => {
const handleResize = () => {
// On larger screens, ensure mobile view is reset
if (!isMobile() && mobileView) {
// Don't reset mobile view state, just let the responsive classes handle it
}
}
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [mobileView])
const fetchFilesInitial = useCallback(async () => {
setInitialFilesLoading(true)
try {
await fetchFiles(params.id)
} finally {
setInitialFilesLoading(false)
}
}, [params.id, fetchFiles])
const fetchBookInfo = useCallback(async () => {
try {
setBookLoading(true)
const response = await fetch(`/api/books?userId=${user?.id}`)
if (!response.ok) {
throw new Error('Failed to fetch book info')
}
const data = await response.json()
const book = data.books?.find((b: any) => b.id === params.id)
if (!book) {
throw new Error('Book not found')
}
setBookInfo(book)
} catch (error) {
console.error('Error fetching book info:', error)
setError(error instanceof Error ? error.message : 'Failed to load book')
} finally {
setBookLoading(false)
}
}, [user?.id, params.id])
useEffect(() => {
if (user && params.id && !isInitializedRef.current) {
fetchBookInfo()
fetchFilesInitial()
isInitializedRef.current = true
}
}, [user, params.id, fetchBookInfo, fetchFilesInitial])
const handleFileSelect = (file: FileSystemItem | null) => {
setSelectedFile(file)
// On mobile, switch to editor view when a file is selected
if (file && file.type === 'file' && isMobile()) {
setMobileView('editor')
}
}
const handleFileContentChange = async (content: string) => {
if (selectedFile && selectedFile.type === 'file') {
try {
await updateItem(params.id, selectedFile.id, { content })
} catch (error) {
console.error('Error saving file content:', error)
// Could show an error toast here
}
}
}
const handleFileOperationComplete = useCallback(async () => {
console.log('๐ BookEditor: AI file operation completed, refreshing file system...')
try {
// Force refresh the file system (bypasses visibility checks and caching)
await forceRefreshFiles()
// Also refresh differences tab if it exists
if ((window as any).refreshDifferencesTab) {
(window as any).refreshDifferencesTab()
}
console.log('โ
BookEditor: File system refresh completed')
} catch (error) {
console.error('โ BookEditor: Error refreshing files after AI operation:', error)
}
}, [forceRefreshFiles])
const handleViewDiff = () => {
console.log('๐ BookEditor: handleViewDiff called')
// Check if we have diff info from the differences tab
const currentDiffInfo = (window as any).currentDiffInfo
if (currentDiffInfo) {
console.log('๐ BookEditor: Found diff info, showing DiffViewer:', currentDiffInfo)
setDiffInfo(currentDiffInfo)
setShowDiffMode(true)
} else {
// Legacy: Trigger diff mode in the editor
const editorToggleDiffMode = (window as any).editorToggleDiffMode
if (editorToggleDiffMode && typeof editorToggleDiffMode === 'function') {
console.log('๐ BookEditor: Calling editorToggleDiffMode')
editorToggleDiffMode()
} else {
console.log('โ BookEditor: editorToggleDiffMode not available')
}
}
}
const handleCloseDiff = () => {
console.log('๐ BookEditor: Closing diff mode')
setShowDiffMode(false)
setDiffInfo(null)
// Clear the global diff info
;(window as any).currentDiffInfo = null
}
// Listen for close diff mode events from other components
useEffect(() => {
const handleCloseDiffEvent = () => {
handleCloseDiff()
}
const handleFileOperationEvent = (event: CustomEvent) => {
console.log('๐ BookEditor: File operation completed:', event.detail)
// Trigger file system refresh
handleFileOperationComplete()
}
const handleAIFileOperationEvent = (event: CustomEvent) => {
console.log('๐ค BookEditor: AI file operation completed:', event.detail)
// Trigger file system refresh after AI operations
handleFileOperationComplete()
}
if (typeof window !== 'undefined') {
window.addEventListener('close-diff-mode', handleCloseDiffEvent)
window.addEventListener('file-operation-completed', handleFileOperationEvent as EventListener)
window.addEventListener('ai-file-operation-completed', handleAIFileOperationEvent as EventListener)
return () => {
window.removeEventListener('close-diff-mode', handleCloseDiffEvent)
window.removeEventListener('file-operation-completed', handleFileOperationEvent as EventListener)
window.removeEventListener('ai-file-operation-completed', handleAIFileOperationEvent as EventListener)
}
}
}, [handleFileOperationComplete])
const handleEditorReady = (editor: any) => {
setEditorInstance(editor)
}
// Auto-select last text file in root when files are first loaded
useEffect(() => {
if (files.length > 0 && !selectedFile && !initialFilesLoading) {
// Find text files in the root level (no parent_id)
const rootTextFiles = files.filter(file =>
file.type === 'file' &&
file.file_extension &&
['txt', 'md', 'markdown', 'html', 'htm', 'json'].includes(file.file_extension.toLowerCase())
)
if (rootTextFiles.length > 0) {
// Select the last text file based on sort_order (highest sort_order = last)
const lastTextFile = rootTextFiles.reduce((latest, current) =>
(current.sort_order || 0) > (latest.sort_order || 0) ? current : latest
)
setSelectedFile(lastTextFile)
}
}
}, [files, selectedFile, initialFilesLoading])
// Check for GitHub OAuth data and switch to version control tab
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search)
const hasGitHubData = urlParams.get('repositories') && urlParams.get('accessToken') && urlParams.get('githubUsername')
if (hasGitHubData && activeTab !== 'differences') {
setActiveTab('differences')
}
}, [activeTab])
// Update selectedFile when files tree changes
useEffect(() => {
if (selectedFile) {
// Find the updated version of the currently selected file
const findFileInTree = (files: (FileSystemItem & { children?: FileSystemItem[] })[], targetId: string): FileSystemItem | null => {
for (const file of files) {
if (file.id === targetId) {
return file
}
if (file.children) {
const found = findFileInTree(file.children, targetId)
if (found) return found
}
}
return null
}
const updatedFile = findFileInTree(files, selectedFile.id)
if (updatedFile) {
// Only update if the content has actually changed to prevent unnecessary re-renders
const contentChanged = updatedFile.content !== selectedFile.content
const nameChanged = updatedFile.name !== selectedFile.name
if (contentChanged || nameChanged) {
setSelectedFile(updatedFile)
}
}
}
}, [files, selectedFile, selectedFile?.id, selectedFile?.content, selectedFile?.name])
const renderTabContent = () => {
// Use mobileTab for mobile view, activeTab for desktop
const currentTab = isMobile() ? mobileTab : activeTab
switch (currentTab) {
case 'explorer':
return (
<ExplorerTab
files={files}
onFileSelect={handleFileSelect}
selectedFile={selectedFile}
projectName={bookInfo?.title || 'Loading...'}
bookId={params.id}
createItem={createItem}
updateItem={updateItem}
deleteItem={deleteItem}
loading={filesLoading}
/>
)
case 'search':
return <UnifiedSearchTab bookId={params.id} onFileSelect={handleFileSelect} />
case 'differences':
return (
<DifferencesTab
bookId={params.id}
onFileSelect={handleFileSelect}
onRequestDiff={handleViewDiff}
/>
)
default:
return null
}
}
if (authLoading || bookLoading || initialFilesLoading) {
return <BookEditorSkeleton />
}
if (!user) {
return (
<div className='h-screen flex items-center justify-center bg-slate-900'>
<div className='max-w-md w-full bg-slate-800 rounded-lg shadow-lg p-8 text-center border border-slate-700'>
<h1 className='text-2xl font-bold text-white mb-4'>
Sign in Required
</h1>
<p className='text-slate-300 mb-6'>
You need to sign in to access your book editor.
</p>
<LoginButton />
</div>
</div>
)
}
if (error) {
return (
<div className='h-screen flex items-center justify-center bg-slate-900'>
<div className='max-w-md w-full bg-slate-800 rounded-lg shadow-lg p-8 text-center border border-slate-700'>
<h1 className='text-2xl font-bold text-red-400 mb-4'>
Error Loading Book
</h1>
<p className='text-slate-300 mb-6'>{error}</p>
<button
onClick={() => router.push('/dashboard')}
className='px-4 py-2 bg-slate-700 text-white rounded-md hover:bg-slate-600 transition-colors'
>
Back to Books
</button>
</div>
</div>
)
}
return (
<div className='h-screen flex flex-col md:flex-row bg-black relative overflow-hidden book-editor-page'>
{/* Simplified background for better performance */}
<div className="absolute inset-0 bg-gradient-to-br from-black via-gray-950 to-black pointer-events-none" />
{/* Reduced animated elements for better performance */}
<div className="absolute inset-0 opacity-20 pointer-events-none">
<div className="absolute top-0 left-1/4 w-64 h-64 bg-gradient-to-r from-blue-600/10 to-purple-600/10 rounded-full blur-2xl" />
<div className="absolute bottom-0 right-1/4 w-64 h-64 bg-gradient-to-r from-purple-600/10 to-pink-600/10 rounded-full blur-2xl" />
</div>
{/* Desktop Layout - Three columns with resizable panels */}
<div className="hidden md:flex w-full relative z-10">
{/* Left Panel - File Explorer */}
<ResizablePanel
side="left"
minWidth={200}
maxWidth={500}
defaultWidth={280}
persistKey={`book_${params.id}_explorer`}
className="bg-slate-900/60 border-r border-slate-700/50"
>
<div className="h-full flex flex-col">
<div className='h-12 bg-slate-800/50 border-b border-slate-700/50'>
<div className='grid grid-cols-4 h-12'>
<button
className="flex items-center justify-center text-sm transition-all duration-200 relative group text-slate-400 hover:text-slate-200"
onClick={() => router.push('/dashboard')}
>
<div className="absolute inset-0 bg-gradient-to-r from-blue-500/10 to-purple-500/10 rounded-lg transition-all duration-200 opacity-0 group-hover:opacity-100" />
<div className="relative">
<IoArrowBackOutline className='w-4 h-4' />
</div>
</button>
<button
className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
activeTab === 'explorer'
? 'text-teal-400'
: 'text-slate-400 hover:text-slate-200'
}`}
onClick={() => {
setActiveTab('explorer')
setMobileTab('explorer')
}}
>
<div className={`absolute inset-0 bg-gradient-to-r from-emerald-500/10 to-teal-500/10 rounded-lg transition-all duration-200 ${
activeTab === 'explorer' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`} />
<div className="relative">
<IoDocumentsOutline className='w-4 h-4' />
</div>
</button>
<button
className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
activeTab === 'search'
? 'text-teal-400'
: 'text-slate-400 hover:text-slate-200'
}`}
onClick={() => {
setActiveTab('search')
setMobileTab('search')
}}
>
<div className={`absolute inset-0 bg-gradient-to-r from-amber-500/10 to-orange-500/10 rounded-lg transition-all duration-200 ${
activeTab === 'search' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`} />
<div className="relative">
<IoSearchOutline className='w-4 h-4' />
</div>
</button>
<button
className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
activeTab === 'differences'
? 'text-teal-400'
: 'text-slate-400 hover:text-slate-200'
}`}
onClick={() => {
setActiveTab('differences')
setMobileTab('differences')
}}
>
<div className={`absolute inset-0 bg-gradient-to-r from-violet-500/10 to-purple-500/10 rounded-lg transition-all duration-200 ${
activeTab === 'differences' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`} />
<div className="relative">
<IoGitBranchOutline className='w-4 h-4' />
</div>
</button>
</div>
</div>
<div className="flex-1 overflow-y-auto">
{renderTabContent()}
</div>
</div>
</ResizablePanel>
{/* Center Panel - Editor */}
<div className='flex-1 flex flex-col min-w-0'>
<div className='h-12 bg-slate-800/50 border-b border-slate-700/50 flex items-center px-4 justify-between'>
{showDiffMode && diffInfo ? (
// Diff mode header
<>
<div className="flex items-center gap-3">
<span className="text-sm text-teal-400 font-medium">โจ</span>
<div className="text-sm text-slate-200 font-medium">
Changes in {diffInfo.fileName}
</div>
<div className="flex items-center gap-2 text-xs">
<span className="bg-slate-700/50 text-slate-400 px-2 py-1 rounded border border-slate-600/50">
Original
</span>
<span className="text-slate-500">vs</span>
<span className="bg-slate-700/50 text-slate-300 px-2 py-1 rounded border border-slate-600/50">
Modified
</span>
</div>
</div>
<button
onClick={handleCloseDiff}
className="bg-slate-700/50 hover:bg-slate-600/50 border border-slate-600/50 text-slate-300 hover:text-slate-200 px-2.5 py-1.5 rounded-md text-xs font-medium transition-all duration-150 flex items-center gap-1.5"
>
<IoArrowBackOutline className="w-3.5 h-3.5" />
Back to Editor
</button>
</>
) : (
// Normal mode header
<>
<span className='text-sm text-slate-300 font-medium'>
{selectedFile ? selectedFile.name : 'Select a file to edit'}
</span>
<div className="flex items-center gap-2">
{selectedFile && selectedFile.type === 'file' && (
<DownloadDropdown file={selectedFile} editor={editorInstance} />
)}
{selectedFile && selectedFile.type === 'file' && (
<span className='text-xs text-slate-400 bg-slate-700/50 px-2 py-1 rounded-md'>
{selectedFile.file_extension?.toUpperCase() || 'TXT'}
</span>
)}
</div>
</>
)}
</div>
<div className='flex-1'>
{showDiffMode && diffInfo ? (
<DiffViewer
originalContent={diffInfo.originalContent}
modifiedContent={diffInfo.modifiedContent}
fileName={diffInfo.fileName}
className="h-full"
/>
) : (
<Editor
file={selectedFile}
onContentChange={handleFileContentChange}
bookId={params.id}
onFileOperationComplete={handleFileOperationComplete}
onDiffModeRequest={handleViewDiff}
onEditorReady={handleEditorReady}
/>
)}
</div>
</div>
{/* Right Panel - Chat */}
<ResizablePanel
side="right"
minWidth={300}
maxWidth={700}
defaultWidth={450}
persistKey={`book_${params.id}_chat`}
className="bg-slate-800/60 border-l border-slate-700/50"
>
<ChatPanel
bookId={params.id}
onFileOperationComplete={handleFileOperationComplete}
onViewDiff={handleViewDiff}
onFileSelect={handleFileSelect}
/>
</ResizablePanel>
</div>
{/* Mobile Layout - Single column with bottom navigation */}
<div className="flex-1 flex md:hidden flex-col relative z-10 overflow-hidden">
{/* Mobile view content */}
{mobileView === 'explorer' && (
<div className="flex-1 bg-slate-800/60 flex flex-col min-h-0">
<div className='h-12 bg-slate-800/50 border-b border-slate-700/50'>
<div className='grid grid-cols-4 h-12'>
<button
className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
mobileTab === 'back'
? 'text-teal-400'
: 'text-slate-400 hover:text-slate-200'
}`}
onClick={() => router.push('/dashboard')}
>
<div className={`absolute inset-0 bg-gradient-to-r from-blue-500/10 to-purple-500/10 rounded-lg transition-all duration-200 ${
mobileTab === 'back' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`} />
<div className="relative">
<IoArrowBackOutline className='w-4 h-4' />
</div>
</button>
<button
className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
mobileTab === 'explorer'
? 'text-teal-400'
: 'text-slate-400 hover:text-slate-200'
}`}
onClick={() => {
setMobileTab('explorer')
setActiveTab('explorer')
}}
>
<div className={`absolute inset-0 bg-gradient-to-r from-emerald-500/10 to-teal-500/10 rounded-lg transition-all duration-200 ${
mobileTab === 'explorer' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`} />
<div className="relative">
<IoDocumentsOutline className='w-4 h-4' />
</div>
</button>
<button
className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
mobileTab === 'search'
? 'text-teal-400'
: 'text-slate-400 hover:text-slate-200'
}`}
onClick={() => {
setMobileTab('search')
setActiveTab('search')
}}
>
<div className={`absolute inset-0 bg-gradient-to-r from-amber-500/10 to-orange-500/10 rounded-lg transition-all duration-200 ${
mobileTab === 'search' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`} />
<div className="relative">
<IoSearchOutline className='w-4 h-4' />
</div>
</button>
<button
className={`flex items-center justify-center text-sm transition-all duration-200 relative group ${
mobileTab === 'differences'
? 'text-teal-400'
: 'text-slate-400 hover:text-slate-200'
}`}
onClick={() => {
setMobileTab('differences')
setActiveTab('differences')
}}
>
<div className={`absolute inset-0 bg-gradient-to-r from-violet-500/10 to-purple-500/10 rounded-lg transition-all duration-200 ${
mobileTab === 'differences' ? 'opacity-100' : 'opacity-0 group-hover:opacity-100'
}`} />
<div className="relative">
<IoGitBranchOutline className='w-4 h-4' />
</div>
</button>
</div>
</div>
<div className="flex-1 overflow-y-auto min-h-0">
{renderTabContent()}
</div>
</div>
)}
{mobileView === 'editor' && (
<div className="flex-1 flex flex-col">
<div className='h-12 bg-slate-800/50 border-b border-slate-700/50 flex items-center px-4 justify-between'>
{showDiffMode && diffInfo ? (
// Diff mode header
<>
<div className="flex items-center gap-2">
<span className="text-sm text-teal-400 font-medium">โจ</span>
<div className="text-sm text-slate-200 font-medium">
Changes in {diffInfo.fileName}
</div>
</div>
<button
onClick={handleCloseDiff}
className="bg-slate-700/50 hover:bg-slate-600/50 border border-slate-600/50 text-slate-300 hover:text-slate-200 px-2 py-1 rounded-md text-xs font-medium transition-all duration-150 flex items-center gap-1"
>
<IoArrowBackOutline className="w-3 h-3" />
Back
</button>
</>
) : (
// Normal mode header
<>
<span className='text-sm text-slate-300 font-medium'>
{selectedFile ? selectedFile.name : 'Select a file to edit'}
</span>
<div className="flex items-center gap-2">
{selectedFile && selectedFile.type === 'file' && (
<DownloadDropdown file={selectedFile} editor={editorInstance} />
)}
{selectedFile && selectedFile.type === 'file' && (
<span className='text-xs text-slate-400 bg-slate-700/50 px-2 py-1 rounded-md'>
{selectedFile.file_extension?.toUpperCase() || 'TXT'}
</span>
)}
</div>
</>
)}
</div>
<div className='flex-1'>
{showDiffMode && diffInfo ? (
<DiffViewer
originalContent={diffInfo.originalContent}
modifiedContent={diffInfo.modifiedContent}
fileName={diffInfo.fileName}
className="h-full"
/>
) : (
<Editor
file={selectedFile}
onContentChange={handleFileContentChange}
bookId={params.id}
onFileOperationComplete={handleFileOperationComplete}
onDiffModeRequest={handleViewDiff}
onEditorReady={handleEditorReady}
/>
)}
</div>
</div>
)}
{/* Always render ChatPanel to preserve streaming state, but control visibility */}
<div className={`flex-1 flex flex-col min-h-0 overflow-hidden ${
mobileView === 'assistant' ? 'block' : 'hidden'
}`}>
<ChatPanel
bookId={params.id}
onFileOperationComplete={handleFileOperationComplete}
onViewDiff={handleViewDiff}
onFileSelect={handleFileSelect}
/>
</div>
{/* Mobile Bottom Navigation */}
<div className="h-12 bg-slate-900/95 border-t border-slate-700/60 flex items-center justify-around px-2">
<button
className={`flex items-center justify-center py-2 px-4 rounded-xl transition-all duration-200 relative group ${
mobileView === 'explorer'
? 'text-teal-400 bg-teal-500/15 shadow-lg shadow-teal-500/10'
: 'text-slate-400 hover:text-slate-200 hover:bg-slate-700/40'
}`}
onClick={() => setMobileView('explorer')}
>
<div className="flex items-center gap-2">
<IoDocumentsOutline className={`w-4 h-4 ${mobileView === 'explorer' ? 'text-teal-400' : ''}`} />
<span className="text-xs font-medium">Files</span>
</div>
{mobileView === 'explorer' && (
<div className="absolute inset-0 bg-gradient-to-r from-teal-500/10 to-cyan-500/10 rounded-xl" />
)}
</button>
<button
className={`flex items-center justify-center py-2 px-4 rounded-xl transition-all duration-200 relative group ${
mobileView === 'editor'
? 'text-teal-400 bg-teal-500/15 shadow-lg shadow-teal-500/10'
: 'text-slate-400 hover:text-slate-200 hover:bg-slate-700/40'
}`}
onClick={() => setMobileView('editor')}
>
<div className="flex items-center gap-2">
<IoDocumentTextOutline className={`w-4 h-4 ${mobileView === 'editor' ? 'text-teal-400' : ''}`} />
<span className="text-xs font-medium">Editor</span>
</div>
{mobileView === 'editor' && (
<div className="absolute inset-0 bg-gradient-to-r from-teal-500/10 to-cyan-500/10 rounded-xl" />
)}
</button>
<button
className={`flex items-center justify-center py-2 px-4 rounded-xl transition-all duration-200 relative group ${
mobileView === 'assistant'
? 'text-teal-400 bg-teal-500/15 shadow-lg shadow-teal-500/10'
: 'text-slate-400 hover:text-slate-200 hover:bg-slate-700/40'
}`}
onClick={() => setMobileView('assistant')}
>
<div className="flex items-center gap-2">
<IoChatbubblesOutline className={`w-4 h-4 ${mobileView === 'assistant' ? 'text-teal-400' : ''}`} />
<span className="text-xs font-medium">Chat</span>
</div>
{mobileView === 'assistant' && (
<div className="absolute inset-0 bg-gradient-to-r from-teal-500/10 to-cyan-500/10 rounded-xl" />
)}
</button>
</div>
</div>
</div>
)
}